package loader

import (
	"context"
	"fmt"
	"path/filepath"
	"strings"
	"sync"
	"time"
)

// EventProcessor processes filesystem events for intelligent loading
type EventProcessor struct {
	loader           *SmartLoader
	eventBuffer      []FileEvent
	bufferMutex      sync.Mutex
	processingTicker *time.Ticker
}

// NewEventProcessor creates a new event processor
func NewEventProcessor(loader *SmartLoader) *EventProcessor {
	return &EventProcessor{
		loader:           loader,
		eventBuffer:      make([]FileEvent, 0, 1000),
		processingTicker: time.NewTicker(100 * time.Millisecond),
	}
}

// ProcessEvents starts processing filesystem events
func (ep *EventProcessor) ProcessEvents(ctx context.Context) {
	defer ep.processingTicker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case event := <-ep.loader.monitor.Events():
			ep.bufferEvent(event)
		case <-ep.processingTicker.C:
			ep.processBufferedEvents()
		}
	}
}

// bufferEvent adds an event to the buffer
func (ep *EventProcessor) bufferEvent(event FileEvent) {
	ep.bufferMutex.Lock()
	defer ep.bufferMutex.Unlock()

	// Add event to buffer
	ep.eventBuffer = append(ep.eventBuffer, event)

	// Limit buffer size to prevent memory issues
	if len(ep.eventBuffer) > 10000 {
		// Remove oldest events
		ep.eventBuffer = ep.eventBuffer[len(ep.eventBuffer)-10000:]
	}
}

// processBufferedEvents processes all buffered events
func (ep *EventProcessor) processBufferedEvents() {
	ep.bufferMutex.Lock()
	if len(ep.eventBuffer) == 0 {
		ep.bufferMutex.Unlock()
		return
	}

	// Copy events and clear buffer
	events := make([]FileEvent, len(ep.eventBuffer))
	copy(events, ep.eventBuffer)
	ep.eventBuffer = ep.eventBuffer[:0]
	ep.bufferMutex.Unlock()

	// Process events
	for _, event := range events {
		ep.processEvent(event)
	}
}

// processEvent processes a single filesystem event
func (ep *EventProcessor) processEvent(event FileEvent) {
	// Skip non-access events
	if event.EventType != FileAccess {
		return
	}

	// Convert path to storage key
	key := ep.pathToKey(event.Path)

	// Analyze event patterns for intelligent prefetching
	patterns := ep.analyzeAccessPatterns(event)

	// Trigger loading if necessary
	if ep.shouldTriggerLoad(key, event, patterns) {
		ep.loader.HandleFileEvent(event)
	}

	// Update prefetch patterns
	if ep.loader.config.PrefetchEnabled {
		ep.updatePrefetchPatterns(event, patterns)
	}
}

// pathToKey converts filesystem path to storage key
func (ep *EventProcessor) pathToKey(path string) string {
	// Simple implementation - can be enhanced based on storage backend
	return path
}

// analyzeAccessPatterns analyzes access patterns for intelligent prefetching
func (ep *EventProcessor) analyzeAccessPatterns(event FileEvent) *AccessPatterns {
	patterns := &AccessPatterns{
		Directory:  filepath.Dir(event.Path),
		Extension:  filepath.Ext(event.Path),
		Filename:   filepath.Base(event.Path),
		Timestamp:  event.Timestamp,
	}

	// Analyze sequential patterns
	patterns.Sequential = ep.detectSequentialPattern(event)

	// Analyze directory access patterns
	patterns.DirectoryAccess = ep.analyzeDirectoryAccess(event)

	// Analyze temporal patterns
	patterns.Temporal = ep.analyzeTemporalPattern(event)

	return patterns
}

// detectSequentialPattern detects sequential file access patterns
func (ep *EventProcessor) detectSequentialPattern(event FileEvent) bool {
	// Simple heuristic: check if files with similar names are accessed
	base := strings.TrimSuffix(filepath.Base(event.Path), filepath.Ext(event.Path))

	// Look for numeric patterns in filename
	if strings.Contains(base, "_") || strings.Contains(base, "-") {
		parts := strings.FieldsFunc(base, func(r rune) bool {
			return r == '_' || r == '-'
		})

		for _, part := range parts {
			if isNumeric(part) {
				return true
			}
		}
	}

	return false
}

// analyzeDirectoryAccess analyzes directory access patterns
func (ep *EventProcessor) analyzeDirectoryAccess(event FileEvent) DirectoryAccessPattern {
	// Simple heuristic: count accesses to files in the same directory
	// This could be enhanced with historical data
	return DirectoryAccessPattern{
		Directory:       filepath.Dir(event.Path),
		AccessCount:     1, // Would be incremented with historical data
		LastAccessTime:  event.Timestamp,
		FileTypes:       []string{filepath.Ext(event.Path)},
	}
}

// analyzeTemporalPattern analyzes temporal access patterns
func (ep *EventProcessor) analyzeTemporalPattern(event FileEvent) TemporalPattern {
	accessTime := time.Unix(event.Timestamp, 0)

	return TemporalPattern{
		HourOfDay:     accessTime.Hour(),
		DayOfWeek:     int(accessTime.Weekday()),
		AccessPattern: "immediate", // Could be enhanced with machine learning
		Frequency:     1,           // Would be calculated with historical data
	}
}

// shouldTriggerLoad determines if a file access should trigger loading
func (ep *EventProcessor) shouldTriggerLoad(key string, event FileEvent, patterns *AccessPatterns) bool {
	// Check if file is already loaded or being loaded
	if !ep.loader.shouldTriggerLoad(key) {
		return false
	}

	// Apply intelligent heuristics

	// 1. Sequential access pattern - high priority
	if patterns.Sequential {
		return true
	}

	// 2. Directory with high access frequency
	if patterns.DirectoryAccess.AccessCount > 3 {
		return true
	}

	// 3. Common file types (executables, libraries, configs)
	ext := strings.ToLower(filepath.Ext(event.Path))
	commonTypes := []string{".so", ".dll", ".exe", ".bin", ".conf", ".config", ".json", ".yaml", ".yml"}
	for _, commonType := range commonTypes {
		if ext == commonType {
			return true
		}
	}

	// 4. Files in critical directories
	criticalDirs := []string{"/bin", "/sbin", "/usr/bin", "/usr/sbin", "/etc", "/lib", "/usr/lib"}
	for _, criticalDir := range criticalDirs {
		if strings.HasPrefix(event.Path, criticalDir) {
			return true
		}
	}

	return false
}

// updatePrefetchPatterns updates prefetch patterns based on events
func (ep *EventProcessor) updatePrefetchPatterns(event FileEvent, patterns *AccessPatterns) {
	// Add related files to prefetch queue based on patterns

	// 1. Sequential prefetching
	if patterns.Sequential {
		ep.addSequentialPrefetch(event.Path)
	}

	// 2. Directory-based prefetching
	if patterns.DirectoryAccess.AccessCount > 2 {
		ep.addDirectoryPrefetch(event.Path)
	}

	// 3. Temporal-based prefetching
	ep.addTemporalPrefetch(event.Path, patterns.Temporal)
}

// addSequentialPrefetch adds sequential files to prefetch queue
func (ep *EventProcessor) addSequentialPrefetch(path string) {
	dir := filepath.Dir(path)
	base := strings.TrimSuffix(filepath.Base(path), filepath.Ext(path))
	ext := filepath.Ext(path)

	// Generate next sequential file names
	for i := 1; i <= 3; i++ {
		// Try different sequential patterns
		patterns := []string{
			fmt.Sprintf("%s_%d%s", base, i, ext),
			fmt.Sprintf("%s-%d%s", base, i, ext),
			fmt.Sprintf("%s.%d%s", base, i, ext),
		}

		for _, pattern := range patterns {
			sequentialPath := filepath.Join(dir, pattern)
			key := ep.pathToKey(sequentialPath)
			ep.loader.prefetchQueue.Add(key, 0.7) // Medium priority
		}
	}
}

// addDirectoryPrefetch adds files from the same directory to prefetch queue
func (ep *EventProcessor) addDirectoryPrefetch(path string) {
	// In a real implementation, we would scan the directory
	// For now, we'll add common files that might be related
	commonFiles := []string{"config", "settings", "metadata", "index", "readme"}
	ext := filepath.Ext(path)

	for _, commonFile := range commonFiles {
		relatedPath := filepath.Join(filepath.Dir(path), commonFile+ext)
		key := ep.pathToKey(relatedPath)
		ep.loader.prefetchQueue.Add(key, 0.5) // Low priority
	}
}

// addTemporalPrefetch adds files based on temporal patterns
func (ep *EventProcessor) addTemporalPrefetch(path string, pattern TemporalPattern) {
	// Add files that are commonly accessed at the same time
	// This is a simplified implementation

	if pattern.HourOfDay >= 9 && pattern.HourOfDay <= 17 {
		// Business hours - prioritize business-related files
		ep.loader.prefetchQueue.Add(ep.pathToKey(path), 0.8)
	} else {
		// Non-business hours - lower priority
		ep.loader.prefetchQueue.Add(ep.pathToKey(path), 0.3)
	}
}

// Helper functions

func isNumeric(s string) bool {
	for _, r := range s {
		if r < '0' || r > '9' {
			return false
		}
	}
	return true
}

// AccessPatterns represents file access patterns
type AccessPatterns struct {
	Directory       string
	Extension       string
	Filename        string
	Timestamp       int64
	Sequential      bool
	DirectoryAccess DirectoryAccessPattern
	Temporal        TemporalPattern
}

// DirectoryAccessPattern represents directory access patterns
type DirectoryAccessPattern struct {
	Directory       string
	AccessCount     int
	LastAccessTime  int64
	FileTypes       []string
}

// TemporalPattern represents temporal access patterns
type TemporalPattern struct {
	HourOfDay     int
	DayOfWeek     int
	AccessPattern string
	Frequency     int
}